package cn.stylefeng.guns.gateway.core.filters.factory;

import cn.hutool.core.util.StrUtil;
import cn.stylefeng.guns.gateway.modular.cache.ResourceRedisCache;
import cn.stylefeng.guns.gateway.modular.validate.ApiAuthService;
import cn.stylefeng.guns.gateway.modular.validate.TokenValidateService;
import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi;
import cn.stylefeng.roses.kernel.micro.api.exception.MicroException;
import cn.stylefeng.roses.kernel.micro.api.exception.enums.GatewayExceptionEnum;
import cn.stylefeng.roses.kernel.scanner.api.pojo.resource.ResourceDefinition;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;

import javax.annotation.Resource;

/**
 * 认证过滤器，判断当前用户是否带有登录的token
 *
 * @author fengshuonan
 * @date 2021/5/12 22:20
 */
public class ApiAuthGatewayFilterFactory extends AbstractGatewayFilterFactory {

    @Resource
    private ApiAuthService apiAuthService;

    @Resource
    private TokenValidateService tokenValidateService;

    @Resource
    private SessionManagerApi sessionManagerApi;

    @Resource
    private ResourceRedisCache resourceRedisCache;

    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {

            // 1. 获取当前请求的路径
            ServerHttpRequest request = exchange.getRequest();
            String currentRequestPath = request.getPath().toString();
            currentRequestPath = currentRequestPath.replaceAll("/+", "/");

            // 请求token
            String token = tokenValidateService.getToken(request);

            // 如果token不为空，则先判断是否登录过期了，过期了就直接打回，不过期不做处理
            if (StrUtil.isNotBlank(token)) {

                // 校验token是否正确
                tokenValidateService.validateToken(token);

                // 校验通过后，刷新用户的session的过期时间
                sessionManagerApi.refreshSession(token);
            }

            // 根据url获取资源详情
            ResourceDefinition resourceDefinition = resourceRedisCache.get(currentRequestPath);

            // 找不到对应的资源，则打回请求，一切url以资源扫描中为准
            if (resourceDefinition == null) {
                throw new MicroException(GatewayExceptionEnum.CACHE_URL_NULL);
            }

            // 校验接口权限
            apiAuthService.validate(token, resourceDefinition);

            return chain.filter(exchange.mutate().request(request).build());
        };
    }

}
